#ifndef padl_UART_H_
#define padl_UART_H_

#include "target.h"


#define padl_uart_UART0	((padl_uart_UartType *)0xE000C000)
#define padl_uart_UART1	((padl_uart_UartType *)0xE0010000)
#define padl_uart_UART2	((padl_uart_UartType *)0xE0078000)
#define padl_uart_UART3	((padl_uart_UartType *)0xE007C000)


typedef struct {
	  union {
		  REGISTER RO U8 		RBR;
		  REGISTER WO U8 		THR;
		  REGISTER RW U8 		DLL;
		  U32 					RESERVED0;
	  };
	  union {
		  REGISTER RW U8  		DLM;
		  union {
			  REGISTER RW U32 		IER;
			  struct {
				  REGISTER RW BOOL RDA : 1;
				  REGISTER RW BOOL THRE : 1;
				  REGISTER RW BOOL RLS : 1;
			  } IER_detailed;
		  };
	  };
	  union {
		  REGISTER RO U32	 	IIR;
		  REGISTER WO U8  		FCR;
	  };
	  union{
		  REGISTER RW U8  		LCR;
		  struct {
			  REGISTER RW U8 wordLength : 2;
			  REGISTER RW U8 stopBit : 1;
			  REGISTER RW BOOL parityEnable : 1;
			  REGISTER RW U8 parity : 2;
			  REGISTER RW BOOL breakControl : 1;
			  REGISTER RW BOOL divisorLatchAccess : 1;
		  }LCR_detailed;
	  };
	  U8  						RESERVED1[7];
	  union {
		  REGISTER RO U8	  		LSR;
		  struct {
			  REGISTER RO BOOL RDR : 1;
			  REGISTER RO BOOL OE : 1;
			  REGISTER RO BOOL PE : 1;
			  REGISTER RO BOOL FE : 1;
			  REGISTER RO BOOL BI : 1;
			  REGISTER RO BOOL THRE : 1;
			  REGISTER RO BOOL TEMT : 1;
			  REGISTER RO BOOL RXFE : 1;
		  }LSR_detailed;
	  };
	  U8  						RESERVED2[7];
	  REGISTER RW U8			SCR;
	  U8  						RESERVED3[3];
	  REGISTER RW U32			ACR;
	  REGISTER RW U8			ICR;
	  U8  						RESERVED4[3];
	  union{
		  REGISTER RW U8		FDR;
		  struct {
			  REGISTER RW U8 DIVADDVAL : 4;
			  REGISTER RW U8 MULVAL : 4;
		  } FDR_detailed;
	  };
	  U8  						RESERVED5[7];
	  REGISTER RW U8			TER;
} padl_uart_UartType;

// Data Transmited interrupt
#define padl_uart_IIR_THRE		0x01
// Receive Data Available interrupt
#define padl_uart_IIR_RDA		0x02
// RX line status interrupts
#define padl_uart_IIR_RLS		0x03
// Character Time-out Indicator interrupt
#define padl_uart_IIR_CTI		0x06

// Data length options
#define padl_uart_FDR_5_BITS		0x00
#define padl_uart_FDR_6_BITS		0x01
#define padl_uart_FDR_7_BITS		0x02
#define padl_uart_FDR_8_BITS		0x03

// Stop bit options
#define padl_uart_FDR_1_STOP_BIT		0
#define padl_uart_FDR_2_STOP_BIT		1

// Parity options
#define padl_uart_FDR_ODD_PARITY			0
#define padl_uart_FDR_EVEN_PARITY 		1
#define padl_uart_FDR_FORCED_1_PARITY	2
#define padl_uart_FDR_FORCED_0_PARITY	3


// Obs.: Before reading data, padl_uart_GET_LINE_STATUS must be called.
#define padl_uart_READ_RECEIVED_DATA(uart) \
	(uart)->RBR

#define padl_uart_SEND_DATA(uart, data) \
	(uart)->THR = data

#define padl_uart_GET_BAUDRATE_DIVISOR(uart) \
	((U16)(((uart)->DLM << 8) | ((uart)->DLL)))

// Obs.: Before set baudrate, divisor latch access muste be enabled (padl_uart_ENABLE_BAUDRATE_DLA)
#define padl_uart_SET_BAUDRATE_DIVISOR(uart, divisor) \
	(uart)->DLL = (divisor & 0xFF);\
	(uart)->DLM = (divisor >> 8);

#define padl_uart_GET_FRACTIONAL_BAUDRATE_DIVISOR(uart) \
		((uart)->FDR_detailed.DIVADDVAL)
#define padl_uart_SET_FRACTIONAL_BAUDRATE_DIVISOR(uart, divisor) \
	((uart)->FDR_detailed.DIVADDVAL = divisor)

#define padl_uart_GET_FRACTIONAL_BAUDRATE_MULTIPLIER(uart) \
	((uart)->FDR_detailed.MULVAL)
#define padl_uart_SET_FRACTIONAL_BAUDRATE_MULTIPLIER(uart, multiplier) \
	((uart)->FDR_detailed.MULVAL = multiplier)

#define padl_uart_ENABLE_RDA_INTERRUPT(uart) \
	((uart)->IER_detailed.RDA = TRUE)
#define padl_uart_DISABLE_RDA_INTERRUPT(uart) \
	((uart)->IER_detailed.RDA = FALSE)
#define padl_uart_IS_ENABLE_RDA_INTERRUPT(uart) \
	((uart)->IER_detailed.RDA)

#define padl_uart_ENABLE_THRE_INTERRUPT(uart) \
	((uart)->IER_detailed.THRE = TRUE)
#define padl_uart_DISABLE_THRE_INTERRUPT(uart) \
	((uart)->IER_detailed.THRE = FALSE)
#define padl_uart_IS_ENABLE_THRE_INTERRUPT(uart) \
	((uart)->IER_detailed.THRE)

#define padl_uart_ENABLE_RLS_INTERRUPT(uart) \
	((uart)->IER_detailed.RLS = TRUE)
#define padl_uart_DISABLE_RLS_INTERRUPT(uart) \
	((uart)->IER_detailed.RLS = FALSE)
#define padl_uart_IS_ENABLE_RLS_INTERRUPT(uart) \
	((uart)->IER_detailed.RLS)

#define padl_uart_GET_INTERRUPT_ID(uart) \
	(((uart)->IIR >> 1) & 0x07)

#define padl_uart_GET_DATA_LENGTH(uart) \
	((uart)->LCR_detailed.wordLength)
#define padl_uart_SET_DATA_LENGTH(uart, setting) \
	((uart)->LCR_detailed.wordLength = setting)

#define padl_uart_GET_STOP_BIT(uart) \
	((uart)->LCR_detailed.stopBit)
#define padl_uart_SET_STOP_BIT(uart, setting) \
	((uart)->LCR_detailed.stopBit = setting)

#define padl_uart_IS_ENABLE_PARITY(uart) \
	((uart)->LCR_detailed.parityEnable)
#define padl_uart_SET_ENABLE_PARITY(uart, enable) \
	((uart)->LCR_detailed.parityEnable = enable)
#define padl_uart_GET_PARITY(uart) \
	((uart)->LCR_detailed.parity)
#define padl_uart_SET_PARITY(uart, setting) \
	((uart)->LCR_detailed.parity = setting)

#define padl_uart_ENABLE_BREAK_TRANSMISSION(uart) \
	((uart)->LCR_detailed.breakControl = 1)
#define padl_uart_DISABLE_BREAK_TRANSMISSION(uart) \
	((uart)->LCR_detailed.breakControl = 0)

#define padl_uart_ENABLE_BAUDRATE_DLA(uart) \
	((uart)->LCR_detailed.divisorLatchAccess = 1)
#define padl_uart_DISABLE_BAUDRATE_DLA(uart) \
	((uart)->LCR_detailed.divisorLatchAccess = 0)

#define padl_uart_IS_RECEIVE_DATA_READY(uart) \
	((uart)->LSR_detailed.RDR)

#define padl_uart_IS_OVERRUN_ERROR(uart) \
	((uart)->LSR_detailed.OE)

#define padl_uart_IS_PARITY_ERROR(uart) \
	((uart)->LSR_detailed.PE)

#define padl_uart_IS_FRAMING_ERROR(uart) \
	((uart)->LSR_detailed.FE)

#define padl_uart_IS_BREAK_INTERRUPT(uart) \
	((uart)->LSR_detailed.BI)

#define padl_uart_IS_TRANSMISSION_READY(uart) \
	((uart)->LSR_detailed.THRE)

#define padl_uart_IS_RX_FIFO_ERROR(uart) \
	((uart)->LSR_detailed.RXFE)


#endif /*padl_UART_H_*/
